package com.jjz.id.config.properties;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.cors.CorsConfiguration;

import java.util.stream.Collectors;

/**
 * @author ZJL
 * @create 2025-05-27-17:03
 * 注册并提供 Spring MVC 使用的全局 CORS（跨域资源共享）配置
 */
@Component
@ConfigurationProperties(
        prefix = "jue.auth.web.cors"
)
@Getter
@Setter
public class JueCorsProperties {
    private static final String DEFAULT_ALLOWED_METHODS = "GET,POST,OPTIONS,PUT,DELETE";
    private static final String DEFAULT_ALLOWED_HEADERS = "Origin,Accept,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization";
    private static final String ALLOW_ALL_ORIGIN = "*";
    //是否允许携带 凭据（如 Cookie、Authorization 头、HTTPS 证书等）。
    private Boolean allowCredentials = false;
    private Long maxAge = 3600L;
    //具体来源域名（非通配符）
    private List<String> allowedOrigins;
    //支持的域名模式
    private List<String> allowedOriginPatterns;
    //
    private List<String> allowedMethods;
    //指定客户端允许携带的自定义请求头，比如允许前端带 X-User-Custom 请求头。
    private List<String> allowedHeaders;


    public CorsConfiguration toCorsConfiguration() {
        PropertyMapper map = PropertyMapper.get();
        CorsConfiguration config = new CorsConfiguration();

        map.from(this::getAllowedOriginPatterns)
                .whenNot(CollectionUtils::isEmpty)
                .to(config::setAllowedOriginPatterns);

        map.from(() -> Optional.ofNullable(this.allowedOrigins)
                        .orElseGet(() -> (this.allowedOriginPatterns != null && !this.allowedOriginPatterns.isEmpty())
                                ? null
                                : Collections.singletonList(ALLOW_ALL_ORIGIN)))
                .to(config::setAllowedOrigins);

        map.from(this::getAllowedHeaders)
                .whenNot(CollectionUtils::isEmpty)
                .to(config::setAllowedHeaders);

        map.from(this::getAllowedMethods)
                .whenNot(CollectionUtils::isEmpty)
                .to(config::setAllowedMethods);

        map.from(this::getMaxAge)
                .to(config::setMaxAge);

        map.from(this::getAllowCredentials)
                .whenNonNull()
                .to(config::setAllowCredentials);

        return config;
    }
    public Long getMaxAge() {
        return this.maxAge;
    }

    public void setMaxAge(Long maxAge) {
        this.maxAge = maxAge;
    }

    public List<String> getAllowedOriginPatterns() {
        return this.allowedOriginPatterns;
    }

    public void setAllowedOriginPatterns(List<String> allowedOriginPatterns) {
        this.allowedOriginPatterns = allowedOriginPatterns;
    }

    public List<String> getAllowedOrigins() {
        return this.allowedOrigins;
    }

    public void setAllowedOrigins(List<String> allowedOrigins) {
        this.allowedOrigins = allowedOrigins;
    }

    public List<String> getAllowedMethods() {
        if (this.allowedMethods != null && this.allowedMethods.size() != 0) {
            return this.allowedMethods;
        } else {
            List<String> defaults = Arrays.stream(DEFAULT_ALLOWED_METHODS.split(",")).collect(Collectors.toList());
            return defaults;
        }
    }

    public void setAllowedMethods(List<String> allowedMethods) {
        this.allowedMethods = allowedMethods;
    }

    public List<String> getAllowedHeaders() {
        if (this.allowedHeaders != null && this.allowedHeaders.size() != 0) {
            return this.allowedHeaders;
        } else {
            List<String> defaults = Arrays.stream(DEFAULT_ALLOWED_HEADERS.split(",")).collect(Collectors.toList());
            return defaults;
        }
    }

    public void setAllowedHeaders(List<String> allowedHeaders) {
        this.allowedHeaders = allowedHeaders;
    }

    public boolean getAllowCredentials() {
        return this.allowCredentials;
    }

    public void setAllowCredentials(boolean allowCredentials) {
        this.allowCredentials = allowCredentials;
    }

}
